package db

import (
	"encoding/json"
	"fmt"
	"strconv"

	"github.com/xwb1989/sqlparser"
)

type TableInfo struct {
	Name          string
	TupleDescInfo TupleDesc
	Level         []Level_strategy
	Vertical      []Vertical_strategy
	Strategy_type int //0代表垂直划分，1代表水平划分,2
}

type Vertical_strategy struct {
	Site          string
	TupleDescInfo TupleDesc
}
type L_strategy struct {
	ItemInfo  Item
	Symbol    string
	Parameter string
}
type Level_strategy struct {
	Site     string
	Strategy []L_strategy
}

func (n *TableInfo) Parse() string {
	data, err := json.Marshal(n)
	if err != nil {
		fmt.Printf("结构体转json错误，错误位置table.go,错误信息: %v\n", err)
	}
	return string(data)
}

func (n *TableInfo) UnParse(s string) {
	err := json.Unmarshal([]byte(s), &n)
	if err != nil {
		fmt.Printf("json转结构体错误，错误位置table.go,错误信息: %v\n", err)
	}
}

func (t *TableInfo) InsertPrime(sql string) ([]string, []string) {
	site_list := []string{}
	sql_list := []string{}
	stmt, _ := sqlparser.Parse(sql)
	stmtInsert, _ := stmt.(*sqlparser.Insert)
	switch t.Strategy_type {
	case 0:
		for _, v := range t.Vertical {
			s := v.Generator_sql_insert(*stmtInsert, t)
			if s != "" {
				site_list = append(site_list, v.Site)
				sql_list = append(sql_list, s)
			}
		}
	case 1:
		for _, l := range t.Level {
			s := l.Generator_sql_insert(*stmtInsert, t)
			if s {
				site_list = append(site_list, l.Site)
				sql_list = append(sql_list, sql)
			}
		}
	}
	return site_list, sql_list
}

func (v Vertical_strategy) Generator_sql_insert(stmt sqlparser.Insert, t *TableInfo) (sql string) {
	table := stmt.Table.Name
	var Rows sqlparser.Values
	switch rows := stmt.Rows.(type) {
	case sqlparser.Values:
		Rows = rows
	}

	column_s := ""
	row_s := ""
	index_s := 0
	if stmt.Columns != nil {
		for idx, column := range stmt.Columns {
			for _, item := range v.TupleDescInfo.getItemList() {
				if column.String() == item.FieldName {
					if index_s != 0 {
						column_s = column_s + ","
						row_s = row_s + ","
					}
					index_s++
					val := v.get_value(Rows, idx)
					row_s = row_s + val
					column_s = column_s + item.FieldName
				}
			}
		}
	} else {
		for idx, item := range t.TupleDescInfo.getItemList() {
			for _, itemV := range v.TupleDescInfo.getItemList() {
				if itemV.FieldName == item.FieldName {
					if index_s != 0 {
						column_s = column_s + ","
						row_s = row_s + ","
					}
					index_s++
					val := v.get_value(Rows, idx)
					row_s = row_s + val
					column_s = column_s + item.FieldName
				}
			}
		}
	}

	sql = fmt.Sprintf("INSERT INTO %s(%s) VALUES(%s);", table, column_s, row_s)
	return sql
}

func (l Level_strategy) Generator_sql_insert(stmt sqlparser.Insert, t *TableInfo) (b bool) {
	Rows, _ := stmt.Rows.(sqlparser.Values)
	if stmt.Columns != nil {
		for idx, column := range stmt.Columns {
			for _, stratage := range l.Strategy {
				if column.String() == stratage.ItemInfo.GetName() {
					return l.get_boo_insert(Rows, idx)
				}
			}
		}
	} else {
		for idx, item := range t.TupleDescInfo.getItemList() {
			for _, stratage := range l.Strategy {
				if item.FieldName == stratage.ItemInfo.GetName() {
					return l.get_boo_insert(Rows, idx)
				}
			}
		}
	}

	return false
}

func (l Level_strategy) get_boo_insert(Rows sqlparser.Values, idx int) (b bool) {
	b = false
	switch val := Rows[0][idx].(type) {
	case *sqlparser.SQLVal:
		if val.Type == 0 { //字符串类型
			return false
		} else if val.Type == 1 {
			values_str := string(val.Val)
			values, err := strconv.Atoi(values_str)
			if err != nil {
				fmt.Printf("插入参数错误: %v\n", err)
			}
			for _, s := range l.Strategy {
				param, _ := strconv.Atoi(s.Parameter)
				if !l.Compare_int(values, s.Symbol, param) {
					return b
				}
			}
		}
	}
	return true
}

func (v Vertical_strategy) get_value(Rows sqlparser.Values, idx int) (res string) {
	switch val := Rows[0][idx].(type) {
	case *sqlparser.SQLVal:
		if val.Type == 0 { //字符串类型
			return "'" + string(val.Val) + "'"
		} else if val.Type == 1 {
			return string(val.Val)
		}
	}
	return ""
}

func (l Level_strategy) Compare_int(value int, symbol string, param int) (b bool) {
	b = false
	switch symbol {
	case EqualStr:
		return value == param
	case LessThanStr:
		return value < param
	case GreaterThanStr:
		return value > param
	case LessEqualStr:
		return value <= param
	case GreaterEqualStr:
		return value >= param
	case NotEqualStr:
		return value != param
	default:
		fmt.Printf("暂不支持该比较: %v\n", "暂不支持该比较")
	}
	return b
}
